diff options
Diffstat (limited to 'src/Kotlin')
| -rw-r--r-- | src/Kotlin/ContentBuilder.kt | 132 | ||||
| -rw-r--r-- | src/Kotlin/DeclarationLinkResolver.kt | 43 | ||||
| -rw-r--r-- | src/Kotlin/DescriptorDocumentationParser.kt | 199 | ||||
| -rw-r--r-- | src/Kotlin/DocumentationBuilder.kt | 653 | ||||
| -rw-r--r-- | src/Kotlin/KotlinAsJavaDocumentationBuilder.kt | 64 | ||||
| -rw-r--r-- | src/Kotlin/KotlinLanguageService.kt | 409 |
6 files changed, 0 insertions, 1500 deletions
diff --git a/src/Kotlin/ContentBuilder.kt b/src/Kotlin/ContentBuilder.kt deleted file mode 100644 index c4bb18de..00000000 --- a/src/Kotlin/ContentBuilder.kt +++ /dev/null @@ -1,132 +0,0 @@ -package org.jetbrains.dokka - -import org.intellij.markdown.MarkdownElementTypes -import org.intellij.markdown.MarkdownTokenTypes -import org.intellij.markdown.html.entities.EntityConverter -import java.util.* - -public fun buildContent(tree: MarkdownNode, linkResolver: (String) -> ContentBlock, inline: Boolean = false): MutableContent { - val result = MutableContent() - if (inline) { - buildInlineContentTo(tree, result, linkResolver) - } - else { - buildContentTo(tree, result, linkResolver) - } - return result -} - -public fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { -// println(tree.toTestString()) - val nodeStack = ArrayDeque<ContentBlock>() - nodeStack.push(target) - - tree.visit {node, processChildren -> - val parent = nodeStack.peek() - - fun appendNodeWithChildren(content: ContentBlock) { - nodeStack.push(content) - processChildren() - parent.append(nodeStack.pop()) - } - - when (node.type) { - MarkdownElementTypes.ATX_1 -> appendNodeWithChildren(ContentHeading(1)) - MarkdownElementTypes.ATX_2 -> appendNodeWithChildren(ContentHeading(2)) - MarkdownElementTypes.ATX_3 -> appendNodeWithChildren(ContentHeading(3)) - MarkdownElementTypes.ATX_4 -> appendNodeWithChildren(ContentHeading(4)) - MarkdownElementTypes.ATX_5 -> appendNodeWithChildren(ContentHeading(5)) - MarkdownElementTypes.ATX_6 -> appendNodeWithChildren(ContentHeading(6)) - MarkdownElementTypes.UNORDERED_LIST -> appendNodeWithChildren(ContentUnorderedList()) - MarkdownElementTypes.ORDERED_LIST -> appendNodeWithChildren(ContentOrderedList()) - MarkdownElementTypes.LIST_ITEM -> appendNodeWithChildren(ContentListItem()) - MarkdownElementTypes.EMPH -> appendNodeWithChildren(ContentEmphasis()) - MarkdownElementTypes.STRONG -> appendNodeWithChildren(ContentStrong()) - MarkdownElementTypes.CODE_SPAN -> appendNodeWithChildren(ContentCode()) - MarkdownElementTypes.CODE_BLOCK, - MarkdownElementTypes.CODE_FENCE -> appendNodeWithChildren(ContentBlockCode()) - MarkdownElementTypes.PARAGRAPH -> appendNodeWithChildren(ContentParagraph()) - - MarkdownElementTypes.INLINE_LINK -> { - val label = node.child(MarkdownElementTypes.LINK_TEXT)?.child(MarkdownTokenTypes.TEXT) - val destination = node.child(MarkdownElementTypes.LINK_DESTINATION) - if (label != null) { - if (destination != null) { - val link = ContentExternalLink(destination.text) - link.append(ContentText(label.text)) - parent.append(link) - } else { - val link = ContentExternalLink(label.text) - link.append(ContentText(label.text)) - parent.append(link) - } - } - } - MarkdownElementTypes.SHORT_REFERENCE_LINK, - MarkdownElementTypes.FULL_REFERENCE_LINK -> { - val label = node.child(MarkdownElementTypes.LINK_LABEL)?.child(MarkdownTokenTypes.TEXT) - if (label != null) { - val link = linkResolver(label.text) - val linkText = node.child(MarkdownElementTypes.LINK_TEXT)?.child(MarkdownTokenTypes.TEXT) - link.append(ContentText(linkText?.text ?: label.text)) - parent.append(link) - } - } - MarkdownTokenTypes.WHITE_SPACE, - MarkdownTokenTypes.EOL -> { - if (keepWhitespace(nodeStack.peek()) && node.parent?.children?.last() != node) { - parent.append(ContentText(node.text)) - } - } - - MarkdownTokenTypes.CODE -> { - val block = ContentBlockCode() - block.append(ContentText(node.text)) - parent.append(block) - } - - MarkdownTokenTypes.TEXT -> { - fun createEntityOrText(text: String): ContentNode { - if (text == "&" || text == """ || text == "<" || text == ">") { - return ContentEntity(text) - } - if (text == "&") { - return ContentEntity("&") - } - val decodedText = EntityConverter.replaceEntities(text, true, true) - if (decodedText != text) { - return ContentEntity(text) - } - return ContentText(text) - } - - parent.append(createEntityOrText(node.text)) - } - - MarkdownTokenTypes.COLON, - MarkdownTokenTypes.DOUBLE_QUOTE, - MarkdownTokenTypes.LT, - MarkdownTokenTypes.GT, - MarkdownTokenTypes.LPAREN, - MarkdownTokenTypes.RPAREN, - MarkdownTokenTypes.LBRACKET, - MarkdownTokenTypes.RBRACKET, - MarkdownTokenTypes.CODE_FENCE_CONTENT -> { - parent.append(ContentText(node.text)) - } - else -> { - processChildren() - } - } - } -} - -private fun keepWhitespace(node: ContentNode) = node is ContentParagraph || node is ContentSection - -public fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { - val inlineContent = tree.children.singleOrNull { it.type == MarkdownElementTypes.PARAGRAPH }?.children ?: listOf(tree) - inlineContent.forEach { - buildContentTo(it, target, linkResolver) - } -} - diff --git a/src/Kotlin/DeclarationLinkResolver.kt b/src/Kotlin/DeclarationLinkResolver.kt deleted file mode 100644 index 2569bc71..00000000 --- a/src/Kotlin/DeclarationLinkResolver.kt +++ /dev/null @@ -1,43 +0,0 @@ -package org.jetbrains.dokka - -import com.google.inject.Inject -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink - -class DeclarationLinkResolver - @Inject constructor(val resolutionFacade: DokkaResolutionFacade, - val refGraph: NodeReferenceGraph, - val logger: DokkaLogger) { - fun resolveContentLink(fromDescriptor: DeclarationDescriptor, href: String): ContentBlock { - val symbol = try { - val symbols = resolveKDocLink(resolutionFacade, fromDescriptor, null, href.split('.').toList()) - findTargetSymbol(symbols) - } catch(e: Exception) { - null - } - - // don't include unresolved links in generated doc - // assume that if an href doesn't contain '/', it's not an attempt to reference an external file - if (symbol != null) { - return ContentNodeLazyLink(href, { -> refGraph.lookup(symbol.signature()) }) - } - if ("/" in href) { - return ContentExternalLink(href) - } - logger.warn("Unresolved link to $href in doc comment of ${fromDescriptor.signatureWithSourceLocation()}") - return ContentExternalLink("#") - } - - fun findTargetSymbol(symbols: Collection<DeclarationDescriptor>): DeclarationDescriptor? { - if (symbols.isEmpty()) { - return null - } - val symbol = symbols.first() - if (symbol is CallableMemberDescriptor && symbol.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { - return symbol.overriddenDescriptors.firstOrNull() - } - return symbol - } - -}
\ No newline at end of file diff --git a/src/Kotlin/DescriptorDocumentationParser.kt b/src/Kotlin/DescriptorDocumentationParser.kt deleted file mode 100644 index b7705ec9..00000000 --- a/src/Kotlin/DescriptorDocumentationParser.kt +++ /dev/null @@ -1,199 +0,0 @@ -package org.jetbrains.dokka.Kotlin - -import com.google.inject.Inject -import com.intellij.psi.PsiDocCommentOwner -import com.intellij.psi.PsiNamedElement -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.dokka.* -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.idea.kdoc.KDocFinder -import org.jetbrains.kotlin.idea.kdoc.getResolutionScope -import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor -import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtBlockExpression -import org.jetbrains.kotlin.psi.KtDeclarationWithBody -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import org.jetbrains.kotlin.resolve.scopes.ResolutionScope -import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered -import org.jetbrains.kotlin.resolve.source.PsiSourceElement - -class DescriptorDocumentationParser - @Inject constructor(val options: DocumentationOptions, - val logger: DokkaLogger, - val linkResolver: DeclarationLinkResolver, - val resolutionFacade: DokkaResolutionFacade, - val refGraph: NodeReferenceGraph) -{ - fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false): Content = - parseDocumentationAndDetails(descriptor, inline).first - - fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> { - if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) { - return parseJavadoc(descriptor) - } - - val kdoc = KDocFinder.findKDoc(descriptor) ?: findStdlibKDoc(descriptor) - if (kdoc == null) { - if (options.reportUndocumented && !descriptor.isDeprecated() && - descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor && - descriptor !is PropertyAccessorDescriptor) { - logger.warn("No documentation for ${descriptor.signatureWithSourceLocation()}") - } - return Content.Empty to { node -> } - } - var kdocText = kdoc.getContent() - // workaround for code fence parsing problem in IJ markdown parser - if (kdocText.endsWith("```") || kdocText.endsWith("~~~")) { - kdocText += "\n" - } - val tree = parseMarkdown(kdocText) - val content = buildContent(tree, { href -> linkResolver.resolveContentLink(descriptor, href) }, inline) - if (kdoc is KDocSection) { - val tags = kdoc.getTags() - tags.forEach { - when (it.name) { - "sample" -> - content.append(functionBody(descriptor, it.getSubjectName())) - "see" -> - content.addTagToSeeAlso(descriptor, it) - else -> { - val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName()) - val sectionContent = it.getContent() - val markdownNode = parseMarkdown(sectionContent) - buildInlineContentTo(markdownNode, section, { href -> linkResolver.resolveContentLink(descriptor, href) }) - } - } - } - } - return content to { node -> } - } - - /** - * Special case for generating stdlib documentation (the Any class to which the override chain will resolve - * is not the same one as the Any class included in the source scope). - */ - fun findStdlibKDoc(descriptor: DeclarationDescriptor): KDocTag? { - if (descriptor !is CallableMemberDescriptor) { - return null - } - val name = descriptor.name.asString() - if (name == "equals" || name == "hashCode" || name == "toString") { - var deepestDescriptor: CallableMemberDescriptor = descriptor - while (!deepestDescriptor.overriddenDescriptors.isEmpty()) { - deepestDescriptor = deepestDescriptor.overriddenDescriptors.first() - } - if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") { - val anyClassDescriptors = resolutionFacade.resolveSession.getTopLevelClassDescriptors( - FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE) - anyClassDescriptors.forEach { - val anyMethod = it.getMemberScope(listOf()) - .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS, { it == descriptor.name }) - .single() - val kdoc = KDocFinder.findKDoc(anyMethod) - if (kdoc != null) { - return kdoc - } - } - } - } - return null - } - - fun parseJavadoc(descriptor: DeclarationDescriptor): Pair<Content, (DocumentationNode) -> Unit> { - val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi - if (psi is PsiDocCommentOwner) { - val parseResult = JavadocParser(refGraph).parseDocumentation(psi as PsiNamedElement) - return parseResult.content to { node -> - parseResult.deprecatedContent?.let { - val deprecationNode = DocumentationNode("", it, DocumentationNode.Kind.Modifier) - node.append(deprecationNode, DocumentationReference.Kind.Deprecation) - } - } - } - return Content.Empty to { node -> } - } - - fun KDocSection.getTags(): Array<KDocTag> = PsiTreeUtil.getChildrenOfType(this, KDocTag::class.java) ?: arrayOf() - - private fun MutableContent.addTagToSeeAlso(descriptor: DeclarationDescriptor, seeTag: KDocTag) { - val subjectName = seeTag.getSubjectName() - if (subjectName != null) { - val seeSection = findSectionByTag("See Also") ?: addSection("See Also", null) - val link = linkResolver.resolveContentLink(descriptor, subjectName) - link.append(ContentText(subjectName)) - val para = ContentParagraph() - para.append(link) - seeSection.append(para) - } - } - - private fun functionBody(descriptor: DeclarationDescriptor, functionName: String?): ContentNode { - if (functionName == null) { - logger.warn("Missing function name in @sample in ${descriptor.signature()}") - return ContentBlockCode().let() { it.append(ContentText("Missing function name in @sample")); it } - } - val scope = getResolutionScope(resolutionFacade, descriptor) - val rootPackage = resolutionFacade.moduleDescriptor.getPackage(FqName.ROOT) - val rootScope = rootPackage.memberScope - val symbol = resolveInScope(functionName, scope) ?: resolveInScope(functionName, rootScope) - if (symbol == null) { - logger.warn("Unresolved function $functionName in @sample in ${descriptor.signature()}") - return ContentBlockCode().let() { it.append(ContentText("Unresolved: $functionName")); it } - } - val psiElement = DescriptorToSourceUtils.descriptorToDeclaration(symbol) - if (psiElement == null) { - logger.warn("Can't find source for function $functionName in @sample in ${descriptor.signature()}") - return ContentBlockCode().let() { it.append(ContentText("Source not found: $functionName")); it } - } - - val text = when (psiElement) { - is KtDeclarationWithBody -> ContentBlockCode().let() { - val bodyExpression = psiElement.bodyExpression - when (bodyExpression) { - is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}") - else -> bodyExpression!!.text - } - } - else -> psiElement.text - } - - val lines = text.trimEnd().split("\n".toRegex()).toTypedArray().filterNot { it.length == 0 } - val indent = lines.map { it.takeWhile { it.isWhitespace() }.count() }.min() ?: 0 - val finalText = lines.map { it.drop(indent) }.joinToString("\n") - return ContentBlockCode("kotlin").let() { it.append(ContentText(finalText)); it } - } - - private fun resolveInScope(functionName: String, scope: ResolutionScope): DeclarationDescriptor? { - var currentScope = scope - val parts = functionName.split('.') - - var symbol: DeclarationDescriptor? = null - - for (part in parts) { - // short name - val symbolName = Name.guess(part) - val partSymbol = currentScope.getContributedDescriptors(DescriptorKindFilter.ALL, { it == symbolName }) - .filter { it.name == symbolName } - .firstOrNull() - - if (partSymbol == null) { - symbol = null - break - } - currentScope = if (partSymbol is ClassDescriptor) - partSymbol.defaultType.memberScope - else - getResolutionScope(resolutionFacade, partSymbol) - symbol = partSymbol - } - - return symbol - } -} diff --git a/src/Kotlin/DocumentationBuilder.kt b/src/Kotlin/DocumentationBuilder.kt deleted file mode 100644 index 6551ded6..00000000 --- a/src/Kotlin/DocumentationBuilder.kt +++ /dev/null @@ -1,653 +0,0 @@ -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.DocumentationNode.Kind -import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -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.caches.resolve.KotlinCacheService -import org.jetbrains.kotlin.idea.caches.resolve.getModuleInfo -import org.jetbrains.kotlin.idea.kdoc.KDocFinder -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.KtModifierListOwner -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant -import org.jetbrains.kotlin.resolve.constants.ConstantValue -import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.resolve.descriptorUtil.isDocumentedAnnotation -import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver -import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform -import org.jetbrains.kotlin.resolve.source.PsiSourceElement -import org.jetbrains.kotlin.resolve.source.getPsi -import org.jetbrains.kotlin.types.ErrorUtils -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjection - -public data class DocumentationOptions(val outputDir: String, - val outputFormat: String, - val includeNonPublic: Boolean = false, - val reportUndocumented: Boolean = true, - val skipEmptyPackages: Boolean = true, - val skipDeprecated: Boolean = false, - val sourceLinks: List<SourceLinkDefinition>) - -private fun isSamePackage(descriptor1: DeclarationDescriptor, descriptor2: DeclarationDescriptor): Boolean { - val package1 = DescriptorUtils.getParentOfType(descriptor1, PackageFragmentDescriptor::class.java) - val package2 = DescriptorUtils.getParentOfType(descriptor2, PackageFragmentDescriptor::class.java) - return package1 != null && package2 != null && package1.fqName == package2.fqName -} - -interface PackageDocumentationBuilder { - fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder, - packageName: FqName, - packageNode: DocumentationNode, - declarations: List<DeclarationDescriptor>) -} - -class DocumentationBuilder - @Inject constructor(val resolutionFacade: DokkaResolutionFacade, - val descriptorDocumentationParser: DescriptorDocumentationParser, - val options: DocumentationOptions, - val refGraph: NodeReferenceGraph, - val logger: DokkaLogger) -{ - val visibleToDocumentation = setOf(Visibilities.PROTECTED, Visibilities.PUBLIC) - 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) - - fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind) { - refGraph.link(node, descriptor.signature(), kind) - } - - fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: DocumentationReference.Kind) { - 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: Kind): DocumentationNode where T : DeclarationDescriptor, T : Named { - val (doc, callback) = descriptorDocumentationParser.parseDocumentationAndDetails(descriptor, kind == Kind.Parameter) - val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(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 - } - - 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, DocumentationNode.Kind.Modifier) - } - - fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) { - val modifier = descriptor.visibility.normalize().displayName - appendTextNode(modifier, DocumentationNode.Kind.Modifier) - } - - fun DocumentationNode.appendSupertypes(descriptor: ClassDescriptor) { - val superTypes = descriptor.typeConstructor.supertypes - for (superType in superTypes) { - if (!ignoreSupertype(superType)) { - appendType(superType, DocumentationNode.Kind.Supertype) - val superclass = superType?.constructor?.declarationDescriptor - link(superclass, descriptor, DocumentationReference.Kind.Inheritor) - link(descriptor, superclass, DocumentationReference.Kind.Superclass) - } - } - } - - private fun ignoreSupertype(superType: KotlinType): Boolean { - val superClass = superType.constructor.declarationDescriptor as? ClassDescriptor - if (superClass != null) { - val fqName = DescriptorUtils.getFqNameSafe(superClass).asString() - return fqName == "kotlin.Annotation" || fqName == "kotlin.Enum" || fqName == "kotlin.Any" - } - return false - } - - fun DocumentationNode.appendProjection(projection: TypeProjection, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type) { - if (projection.isStarProjection) { - appendTextNode("*", Kind.Type) - } - else { - appendType(projection.type, kind, projection.projectionKind.label) - } - } - - fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: DocumentationNode.Kind = DocumentationNode.Kind.Type, prefix: String = "") { - if (kotlinType == null) - return - val classifierDescriptor = kotlinType.constructor.declarationDescriptor - val name = when (classifierDescriptor) { - is ClassDescriptor -> { - if (classifierDescriptor.isCompanionObject) { - classifierDescriptor.containingDeclaration.name.asString() + - "." + classifierDescriptor.name.asString() - } - else { - classifierDescriptor.name.asString() - } - } - is Named -> classifierDescriptor.name.asString() - else -> "<anonymous>" - } - val node = DocumentationNode(name, Content.Empty, kind) - if (prefix != "") { - node.appendTextNode(prefix, Kind.Modifier) - } - if (kotlinType.isMarkedNullable) { - node.appendTextNode("?", Kind.NullabilityModifier) - } - if (classifierDescriptor != null) { - link(node, classifierDescriptor, - if (classifierDescriptor.isBoringBuiltinClass()) DocumentationReference.Kind.HiddenLink else DocumentationReference.Kind.Link) - } - - append(node, DocumentationReference.Kind.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.filter { it.isDocumented() }.forEach { - val annotationNode = it.build() - if (annotationNode != null) { - append(annotationNode, - if (annotationNode.isDeprecation()) DocumentationReference.Kind.Deprecation else DocumentationReference.Kind.Annotation) - } - } - } - - fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) { - val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return - KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach { - if (psi.hasModifier(it)) { - appendTextNode(it.value, Kind.Modifier) - } - } - } - - fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated" - - fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) { - appendSourceLink(sourceElement.getPsi(), options.sourceLinks) - } - - fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: DocumentationReference.Kind): DocumentationNode? { - // do not include generated code - if (descriptor is CallableMemberDescriptor && descriptor.kind != CallableMemberDescriptor.Kind.DECLARATION) - return null - - if (descriptor.isDocumented()) { - val node = descriptor.build() - append(node, kind) - return node - } - return null - } - - fun DeclarationDescriptor.isDocumented(): Boolean { - return (options.includeNonPublic - || this !is MemberDescriptor - || this.visibility in visibleToDocumentation) && - !isDocumentationSuppressed() && - (!options.skipDeprecated || !isDeprecated()) - } - - fun DocumentationNode.appendMembers(descriptors: Iterable<DeclarationDescriptor>): List<DocumentationNode> { - val nodes = descriptors.map { descriptor -> - if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { - val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull() - if (baseDescriptor != null) { - link(this, baseDescriptor, DocumentationReference.Kind.InheritedMember) - } - null - } - else { - val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original - appendChild(descriptorToUse, DocumentationReference.Kind.Member) - } - } - return nodes.filterNotNull() - } - - fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: DocumentationReference.Kind) { - descriptors.forEach { descriptor -> - val node = appendChild(descriptor, kind) - node?.addReferenceTo(this, DocumentationReference.Kind.TopLevelPage) - } - } - - fun DocumentationModule.appendFragments(fragments: Collection<PackageFragmentDescriptor>, - packageContent: Map<String, Content>, - packageDocumentationBuilder: PackageDocumentationBuilder) { - val allFqNames = fragments.map { it.fqName }.distinct() - - for (packageName in allFqNames) { - val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() } - - if (options.skipEmptyPackages && declarations.none { it.isDocumented() }) continue - logger.info(" package $packageName: ${declarations.count()} declarations") - val packageNode = findOrCreatePackageNode(packageName.asString(), packageContent) - packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode, declarations) - } - } - - fun DeclarationDescriptor.build(): DocumentationNode = when (this) { - is ClassDescriptor -> build() - is ConstructorDescriptor -> build() - is PropertyDescriptor -> build() - is FunctionDescriptor -> build() - is TypeParameterDescriptor -> build() - is ValueParameterDescriptor -> build() - is ReceiverParameterDescriptor -> build() - else -> throw IllegalStateException("Descriptor $this is not known") - } - - fun ClassDescriptor.build(): DocumentationNode { - val kind = when (kind) { - ClassKind.OBJECT -> Kind.Object - ClassKind.INTERFACE -> Kind.Interface - ClassKind.ENUM_CLASS -> Kind.Enum - ClassKind.ANNOTATION_CLASS -> Kind.AnnotationClass - ClassKind.ENUM_ENTRY -> Kind.EnumItem - else -> Kind.Class - } - val node = nodeForDescriptor(this, kind) - node.appendSupertypes(this) - if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) { - node.appendInPageChildren(typeConstructor.parameters, DocumentationReference.Kind.Detail) - val constructorsToDocument = if (getKind() == ClassKind.ENUM_CLASS) - constructors.filter { it.valueParameters.size > 0 } - else - constructors - node.appendMembers(constructorsToDocument) - } - val members = defaultType.memberScope.getContributedDescriptors().filter { it != companionObjectDescriptor } - node.appendMembers(members) - node.appendMembers(staticScope.getContributedDescriptors()).forEach { - it.appendTextNode("static", Kind.Modifier) - } - val companionObjectDescriptor = companionObjectDescriptor - if (companionObjectDescriptor != null) { - node.appendMembers(companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()) - } - node.appendAnnotations(this) - node.appendModifiers(this) - node.appendSourceLink(source) - register(this, node) - return node - } - - fun ConstructorDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, Kind.Constructor) - node.appendInPageChildren(valueParameters, DocumentationReference.Kind.Detail) - register(this, node) - return node - } - - private fun CallableMemberDescriptor.inCompanionObject(): Boolean { - val containingDeclaration = containingDeclaration - if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject ?: false) { - return true - } - val receiver = extensionReceiverParameter - return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false - } - - fun FunctionDescriptor.build(): DocumentationNode { - if (ErrorUtils.containsErrorType(this)) { - logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}") - } - - val node = nodeForDescriptor(this, if (inCompanionObject()) Kind.CompanionObjectFunction else Kind.Function) - - node.appendInPageChildren(typeParameters, DocumentationReference.Kind.Detail) - extensionReceiverParameter?.let { node.appendChild(it, DocumentationReference.Kind.Detail) } - node.appendInPageChildren(valueParameters, DocumentationReference.Kind.Detail) - node.appendType(returnType) - node.appendAnnotations(this) - node.appendModifiers(this) - node.appendSourceLink(source) - - overriddenDescriptors.forEach { - addOverrideLink(it, this) - } - - register(this, node) - return node - } - - fun addOverrideLink(baseClassFunction: CallableMemberDescriptor, overridingFunction: CallableMemberDescriptor) { - val source = baseClassFunction.original.source.getPsi() - if (source != null) { - link(overridingFunction, baseClassFunction, DocumentationReference.Kind.Override) - } else { - baseClassFunction.overriddenDescriptors.forEach { - addOverrideLink(it, overridingFunction) - } - } - } - - fun PropertyDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, if (inCompanionObject()) Kind.CompanionObjectProperty else Kind.Property) - node.appendInPageChildren(typeParameters, DocumentationReference.Kind.Detail) - extensionReceiverParameter?.let { node.appendChild(it, DocumentationReference.Kind.Detail) } - node.appendType(returnType) - node.appendAnnotations(this) - node.appendModifiers(this) - node.appendSourceLink(source) - if (isVar) { - node.appendTextNode("var", DocumentationNode.Kind.Modifier) - } - getter?.let { - if (!it.isDefault) { - node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Getter") - } - } - setter?.let { - if (!it.isDefault) { - node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Setter") - } - } - - overriddenDescriptors.forEach { - addOverrideLink(it, this) - } - - register(this, node) - return node - } - - fun DocumentationNode.addAccessorDocumentation(documentation: Content, prefix: String) { - if (documentation == Content.Empty) return - updateContent { - if (!documentation.children.isEmpty()) { - val section = addSection(prefix, null) - documentation.children.forEach { section.append(it) } - } - documentation.sections.forEach { - val section = addSection("$prefix ${it.tag}", it.subjectName) - it.children.forEach { section.append(it) } - } - } - } - - fun ValueParameterDescriptor.build(): DocumentationNode { - val node = nodeForDescriptor(this, Kind.Parameter) - node.appendType(varargElementType ?: type) - if (declaresDefaultValue()) { - val psi = source.getPsi() as? KtParameter - if (psi != null) { - val defaultValueText = psi.defaultValue?.text - if (defaultValueText != null) { - node.appendTextNode(defaultValueText, Kind.Value) - } - } - } - node.appendAnnotations(this) - node.appendModifiers(this) - if (varargElementType != null && node.details(Kind.Modifier).none { it.name == "vararg" }) { - node.appendTextNode("vararg", Kind.Modifier) - } - register(this, node) - return node - } - - fun TypeParameterDescriptor.build(): DocumentationNode { - val doc = descriptorDocumentationParser.parseDocumentation(this) - val name = name.asString() - val prefix = variance.label - - val node = DocumentationNode(name, doc, DocumentationNode.Kind.TypeParameter) - if (prefix != "") { - node.appendTextNode(prefix, Kind.Modifier) - } - if (isReified) { - node.appendTextNode("reified", Kind.Modifier) |
