aboutsummaryrefslogtreecommitdiff
path: root/src/Kotlin
diff options
context:
space:
mode:
authorDmitry Jemerov <yole@jetbrains.com>2015-12-03 16:22:11 +0100
committerDmitry Jemerov <yole@jetbrains.com>2015-12-03 16:22:49 +0100
commit39631054c58df5841ea268b7002b820ec55f6e0a (patch)
treecefedd8411c859243bd181568e16fcdd372a38c8 /src/Kotlin
parent797cb4732c53bf1e3b2091add8cf731fc436607f (diff)
downloaddokka-39631054c58df5841ea268b7002b820ec55f6e0a.tar.gz
dokka-39631054c58df5841ea268b7002b820ec55f6e0a.tar.bz2
dokka-39631054c58df5841ea268b7002b820ec55f6e0a.zip
restructure Dokka build to use Gradle for everything except for the Maven plugin
Diffstat (limited to 'src/Kotlin')
-rw-r--r--src/Kotlin/ContentBuilder.kt132
-rw-r--r--src/Kotlin/DeclarationLinkResolver.kt43
-rw-r--r--src/Kotlin/DescriptorDocumentationParser.kt199
-rw-r--r--src/Kotlin/DocumentationBuilder.kt653
-rw-r--r--src/Kotlin/KotlinAsJavaDocumentationBuilder.kt64
-rw-r--r--src/Kotlin/KotlinLanguageService.kt409
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 == "&amp;" || text == "&quot;" || text == "&lt;" || text == "&gt;") {
- return ContentEntity(text)
- }
- if (text == "&") {
- return ContentEntity("&amp;")
- }
- 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 = nodeForDescripto