aboutsummaryrefslogtreecommitdiff
path: root/src/Kotlin
diff options
context:
space:
mode:
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 = 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)
- }
-
- for (constraint in upperBounds) {
- if (KotlinBuiltIns.isDefaultBound(constraint)) {
- continue
- }
- node.appendType(constraint, Kind.UpperBound)
- }
-
- for (constraint in lowerBounds) {
- if (KotlinBuiltIns.isNothing(constraint))
- continue
- node.appendType(constraint, Kind.LowerBound)
- }
- return node
- }
-
- fun ReceiverParameterDescriptor.build(): DocumentationNode {
- var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!!
- if ((receiverClass as? ClassDescriptor)?.isCompanionObject ?: false) {
- receiverClass = receiverClass.containingDeclaration!!
- }
- link(receiverClass,
- containingDeclaration,
- DocumentationReference.Kind.Extension)
-
- val node = DocumentationNode(name.asString(), Content.Empty, Kind.Receiver)
- node.appendType(type)
- return node
- }
-
- fun AnnotationDescriptor.build(): DocumentationNode? {
- val annotationClass = type.constructor.declarationDescriptor
- if (annotationClass == null || ErrorUtils.isError(annotationClass)) {
- return null
- }
- val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, DocumentationNode.Kind.Annotation)
- val arguments = allValueArguments.toList().sortedBy { it.first.index }
- arguments.forEach {
- val valueNode = it.second.toDocumentationNode()
- if (valueNode != null) {
- val paramNode = DocumentationNode(it.first.name.asString(), Content.Empty, DocumentationNode.Kind.Parameter)
- paramNode.append(valueNode, DocumentationReference.Kind.Detail)
- node.append(paramNode, DocumentationReference.Kind.Detail)
- }
- }
- return node
- }
-
- fun CompileTimeConstant<Any?>.build(): DocumentationNode? = when (this) {
- is TypedCompileTimeConstant -> constantValue.toDocumentationNode()
- else -> null
- }
-
- fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value?.let { value ->
- when (value) {
- is String ->
- "\"" + StringUtil.escapeStringCharacters(value) + "\""
- is EnumEntrySyntheticClassDescriptor ->
- value.containingDeclaration.name.asString() + "." + value.name.asString()
- else -> value.toString()
- }.let { valueString ->
- DocumentationNode(valueString, Content.Empty, DocumentationNode.Kind.Value)
- }
- }
-}
-
-class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
- override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>) {
- val externalClassNodes = hashMapOf<FqName, DocumentationNode>()
- declarations.forEach { descriptor ->
- with(documentationBuilder) {
- if (descriptor.isDocumented()) {
- val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes)
- parent.appendChild(descriptor, DocumentationReference.Kind.Member)
- }
- }
- }
- }
-}
-
-class KotlinJavaDocumentationBuilder
- @Inject constructor(val documentationBuilder: DocumentationBuilder,
- val logger: DokkaLogger) : JavaDocumentationBuilder
-{
- override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
- val packageNode = module.findOrCreatePackageNode(file.packageName, packageContent)
-
- file.classes.forEach {
- val javaDescriptorResolver = KotlinCacheService.getInstance(file.project).getProjectService(JvmPlatform,
- it.getModuleInfo(), JavaDescriptorResolver::class.java)
-
- val descriptor = javaDescriptorResolver.resolveClass(JavaClassImpl(it))
- if (descriptor == null) {
- logger.warn("Cannot find descriptor for Java class ${it.qualifiedName}")
- }
- else {
- with(documentationBuilder) {
- packageNode.appendChild(descriptor, DocumentationReference.Kind.Member)
- }
- }
- }
- }
-}
-
-private fun AnnotationDescriptor.isDocumented(): Boolean {
- if (source.getPsi() != null && mustBeDocumented()) return true
- val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString()
- return annotationClassName == "kotlin.Extension"
-}
-
-fun AnnotationDescriptor.mustBeDocumented(): Boolean {
- val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false
- return annotationClass.isDocumentedAnnotation()
-}
-
-fun DeclarationDescriptor.isDocumentationSuppressed(): Boolean {
- val doc = KDocFinder.findKDoc(this)
- return doc is KDocSection && doc.findTagByName("suppress") != null
-}
-
-fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any {
- DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated"
-} || (this is ConstructorDescriptor && containingDeclaration.isDeprecated())
-
-fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor,
- externalClassNodes: MutableMap<FqName, DocumentationNode>): DocumentationNode {
- if (descriptor is CallableMemberDescriptor) {
- val extensionClassDescriptor = descriptor.getExtensionClassDescriptor()
- if (extensionClassDescriptor != null && !isSamePackage(descriptor, extensionClassDescriptor) &&
- !ErrorUtils.isError(extensionClassDescriptor)) {
- val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor)
- return externalClassNodes.getOrPut(fqName, {
- val newNode = DocumentationNode(fqName.asString(), Content.Empty, Kind.ExternalClass)
- append(newNode, DocumentationReference.Kind.Member)
- newNode
- })
- }
- }
- return this
-}
-
-fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? {
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- val type = extensionReceiver.type
- return type.constructor.declarationDescriptor as? ClassDescriptor
- }
- return null
-}
-
-fun DeclarationDescriptor.signature(): String = when(this) {
- is ClassDescriptor, is PackageFragmentDescriptor -> DescriptorUtils.getFqName(this).asString()
- is PropertyDescriptor -> containingDeclaration.signature() + "#" + name + receiverSignature()
- is FunctionDescriptor -> containingDeclaration.signature() + "#" + name + parameterSignature()
- is ValueParameterDescriptor -> containingDeclaration.signature() + ":" + name
- is TypeParameterDescriptor -> containingDeclaration.signature() + "<" + name
-
- else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
-}
-
-fun PropertyDescriptor.receiverSignature(): String {
- val receiver = extensionReceiverParameter
- if (receiver != null) {
- return "#" + receiver.type.signature()
- }
- return ""
-}
-
-fun CallableMemberDescriptor.parameterSignature(): String {
- val params = valueParameters.map { it.type }.toArrayList()
- val extensionReceiver = extensionReceiverParameter
- if (extensionReceiver != null) {
- params.add(0, extensionReceiver.type)
- }
- return "(" + params.map { it.signature() }.joinToString() + ")"
-}
-
-fun KotlinType.signature(): String {
- val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>"
- val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString()
- if (typeName == "Array" && arguments.size == 1) {
- return "Array<" + arguments.first().type.signature() + ">"
- }
- return typeName
-}
-
-fun DeclarationDescriptor.signatureWithSourceLocation(): String {
- val signature = signature()
- val sourceLocation = sourceLocation()
- return if (sourceLocation != null) "$signature ($sourceLocation)" else signature
-}
-
-fun DeclarationDescriptor.sourceLocation(): String? {
- if (this is DeclarationDescriptorWithSource) {
- val psi = (this.source as? PsiSourceElement)?.getPsi()
- if (psi != null) {
- val fileName = psi.containingFile.name
- val lineNumber = psi.lineNumber()
- return if (lineNumber != null) "$fileName:$lineNumber" else fileName
- }
- }
- return null
-}
diff --git a/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt b/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt
deleted file mode 100644
index 7a1d591c..00000000
--- a/src/Kotlin/KotlinAsJavaDocumentationBuilder.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.jetbrains.dokka
-
-import com.google.inject.Inject
-import com.intellij.psi.JavaPsiFacade
-import com.intellij.psi.PsiClass
-import com.intellij.psi.PsiNamedElement
-import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser
-import org.jetbrains.kotlin.asJava.KtLightElement
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.lexer.KtTokens
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.psi.KtDeclaration
-import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.KtPropertyAccessor
-
-class KotlinAsJavaDocumentationBuilder
- @Inject constructor(val kotlinAsJavaDocumentationParser: KotlinAsJavaDocumentationParser) : PackageDocumentationBuilder
-{
- override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
- packageName: FqName,
- packageNode: DocumentationNode,
- declarations: List<DeclarationDescriptor>) {
- val project = documentationBuilder.resolutionFacade.project
- val psiPackage = JavaPsiFacade.getInstance(project).findPackage(packageName.asString())
- if (psiPackage == null) {
- documentationBuilder.logger.error("Cannot find Java package by qualified name: ${packageName.asString()}")
- return
- }
-
- val javaDocumentationBuilder = JavaPsiDocumentationBuilder(documentationBuilder.options,
- documentationBuilder.refGraph,
- kotlinAsJavaDocumentationParser)
-
- psiPackage.classes.filter { it is KtLightElement<*, *> }.filter { it.isVisibleInDocumentation() }.forEach {
- javaDocumentationBuilder.appendClasses(packageNode, arrayOf(it))
- }
- }
-
- fun PsiClass.isVisibleInDocumentation() : Boolean {
- val origin: KtDeclaration? = (this as KtLightElement<*, *>).getOrigin()
- return origin?.hasModifier(KtTokens.INTERNAL_KEYWORD) != true &&
- origin?.hasModifier(KtTokens.PRIVATE_KEYWORD) != true
- }
-}
-
-class KotlinAsJavaDocumentationParser
- @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
- val descriptorDocumentationParser: DescriptorDocumentationParser) : JavaDocumentationParser
-{
- override fun parseDocumentation(element: PsiNamedElement): JavadocParseResult {
- val kotlinLightElement = element as? KtLightElement<*, *> ?: return JavadocParseResult.Empty
- val origin = kotlinLightElement.getOrigin() ?: return JavadocParseResult.Empty
- if (origin is KtParameter) {
- // LazyDeclarationResolver does not support setter parameters
- val grandFather = origin.parent?.parent
- if (grandFather is KtPropertyAccessor) {
- return JavadocParseResult.Empty
- }
- }
- val descriptor = resolutionFacade.resolveToDescriptor(origin)
- val content = descriptorDocumentationParser.parseDocumentation(descriptor, origin is KtParameter)
- return JavadocParseResult(content, null)
- }
-}
diff --git a/src/Kotlin/KotlinLanguageService.kt b/src/Kotlin/KotlinLanguageService.kt
deleted file mode 100644
index 0d39f410..00000000
--- a/src/Kotlin/KotlinLanguageService.kt
+++ /dev/null
@@ -1,409 +0,0 @@
-package org.jetbrains.dokka
-
-import org.jetbrains.dokka.LanguageService.RenderMode
-
-/**
- * Implements [LanguageService] and provides rendering of symbols in Kotlin language
- */
-class KotlinLanguageService : LanguageService {
- private val fullOnlyModifiers = setOf("public", "protected", "private", "inline", "noinline", "crossinline", "reified")
-
- override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
- return content {
- when (node.kind) {
- DocumentationNode.Kind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node)
- in DocumentationNode.Kind.classLike -> renderClass(node, renderMode)
-
- DocumentationNode.Kind.EnumItem,
- DocumentationNode.Kind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name)
-
- DocumentationNode.Kind.TypeParameter -> renderTypeParameter(node, renderMode)
- DocumentationNode.Kind.Type,
- DocumentationNode.Kind.UpperBound -> renderType(node, renderMode)
-
- DocumentationNode.Kind.Modifier -> renderModifier(node)
- DocumentationNode.Kind.Constructor,
- DocumentationNode.Kind.Function,
- DocumentationNode.Kind.CompanionObjectFunction -> renderFunction(node, renderMode)
- DocumentationNode.Kind.Property,
- DocumentationNode.Kind.CompanionObjectProperty -> renderProperty(node, renderMode)
- else -> identifier(node.name)
- }
- }
- }
-
- override fun renderName(node: DocumentationNode): String {
- return when (node.kind) {
- DocumentationNode.Kind.Constructor -> node.owner!!.name
- else -> node.name
- }
- }
-
- override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? {
- if (nodes.size < 2) return null
- val receiverKind = nodes.getReceiverKind() ?: return null
- val functionWithTypeParameter = nodes.firstOrNull { it.details(DocumentationNode.Kind.TypeParameter).any() } ?: return null
- return content {
- val typeParameter = functionWithTypeParameter.details(DocumentationNode.Kind.TypeParameter).first()
- if (functionWithTypeParameter.kind == DocumentationNode.Kind.Function) {
- renderFunction(functionWithTypeParameter, RenderMode.SUMMARY, SummarizingMapper(receiverKind, typeParameter.name))
- }
- else {
- renderProperty(functionWithTypeParameter, RenderMode.SUMMARY, SummarizingMapper(receiverKind, typeParameter.name))
- }
- }
- }
-
- private fun List<DocumentationNode>.getReceiverKind(): ReceiverKind? {
- val qNames = map { it.getReceiverQName() }.filterNotNull()
- if (qNames.size != size)
- return null
-
- return ReceiverKind.values.firstOrNull { kind -> qNames.all { it in kind.classes } }
- }
-
- private fun DocumentationNode.getReceiverQName(): String? {
- if (kind != DocumentationNode.Kind.Function && kind != DocumentationNode.Kind.Property) return null
- val receiver = details(DocumentationNode.Kind.Receiver).singleOrNull() ?: return null
- return receiver.detail(DocumentationNode.Kind.Type).qualifiedNameFromType()
- }
-
- companion object {
- private val arrayClasses = setOf(
- "kotlin.Array",
- "kotlin.BooleanArray",
- "kotlin.ByteArray",
- "kotlin.CharArray",
- "kotlin.ShortArray",
- "kotlin.IntArray",
- "kotlin.LongArray",
- "kotlin.FloatArray",
- "kotlin.DoubleArray"
- )
-
- private val arrayOrListClasses = setOf("kotlin.List") + arrayClasses
-
- private val iterableClasses = setOf(
- "kotlin.Collection",
- "kotlin.Sequence",
- "kotlin.Iterable",
- "kotlin.Map",
- "kotlin.String",
- "kotlin.CharSequence") + arrayOrListClasses
- }
-
- private enum class ReceiverKind(val receiverName: String, val classes: Collection<String>) {
- ARRAY("any_array", arrayClasses),
- ARRAY_OR_LIST("any_array_or_list", arrayOrListClasses),
- ITERABLE("any_iterable", iterableClasses),
- }
-
- interface SignatureMapper {
- fun renderReceiver(receiver: DocumentationNode, to: ContentBlock)
- }
-
- private class SummarizingMapper(val kind: ReceiverKind, val typeParameterName: String): SignatureMapper {
- override fun renderReceiver(receiver: DocumentationNode, to: ContentBlock) {
- to.append(ContentIdentifier(kind.receiverName, IdentifierKind.SummarizedTypeName))
- to.text("<$typeParameterName>")
- }
- }
-
- private fun ContentBlock.renderPackage(node: DocumentationNode) {
- keyword("package")
- text(" ")
- identifier(node.name)
- }
-
- private fun ContentBlock.renderList(nodes: List<DocumentationNode>, separator: String = ", ",
- noWrap: Boolean = false, renderItem: (DocumentationNode) -> Unit) {
- if (nodes.none())
- return
- renderItem(nodes.first())
- nodes.drop(1).forEach {
- if (noWrap) {
- symbol(separator.removeSuffix(" "))
- nbsp()
- } else {
- symbol(separator)
- }
- renderItem(it)
- }
- }
-
- private fun ContentBlock.renderLinked(node: DocumentationNode, body: ContentBlock.(DocumentationNode)->Unit) {
- val to = node.links.firstOrNull()
- if (to == null)
- body(node)
- else
- link(to) {
- body(node)
- }
- }
-
- private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) {
- var typeArguments = node.details(DocumentationNode.Kind.Type)
- if (node.name == "Function${typeArguments.count() - 1}") {
- // lambda
- val isExtension = node.annotations.any { it.name == "Extension" }
- if (isExtension) {
- renderType(typeArguments.first(), renderMode)
- symbol(".")
- typeArguments = typeArguments.drop(1)
- }
- symbol("(")
- renderList(typeArguments.take(typeArguments.size - 1), noWrap = true) {
- renderType(it, renderMode)
- }
- symbol(")")
- nbsp()
- symbol("->")
- nbsp()
- renderType(typeArguments.last(), renderMode)
- return
- }
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode, true)
- renderLinked(node) { identifier(it.name, IdentifierKind.TypeName) }
- if (typeArguments.any()) {
- symbol("<")
- renderList(typeArguments, noWrap = true) {
- renderType(it, renderMode)
- }
- symbol(">")
- }
- val nullabilityModifier = node.details(DocumentationNode.Kind.NullabilityModifier).singleOrNull()
- if (nullabilityModifier != null) {
- symbol(nullabilityModifier.name)
- }
- }
-
- private fun ContentBlock.renderModifier(node: DocumentationNode, nowrap: Boolean = false) {
- when (node.name) {
- "final", "public", "var" -> {}
- else -> {
- keyword(node.name)
- if (nowrap) {
- nbsp()
- }
- else {
- text(" ")
- }
- }
- }
- }
-
- private fun ContentBlock.renderTypeParameter(node: DocumentationNode, renderMode: RenderMode) {
- renderModifiersForNode(node, renderMode, true)
-
- identifier(node.name)
-
- val constraints = node.details(DocumentationNode.Kind.UpperBound)
- if (constraints.any()) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(constraints, noWrap=true) {
- renderType(it, renderMode)
- }
- }
- }
- private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- identifier(node.name, IdentifierKind.ParameterName)
- symbol(":")
- nbsp()
- val parameterType = node.detail(DocumentationNode.Kind.Type)
- renderType(parameterType, renderMode)
- val valueNode = node.details(DocumentationNode.Kind.Value).firstOrNull()
- if (valueNode != null) {
- nbsp()
- symbol("=")
- nbsp()
- text(valueNode.name)
- }
- }
-
- private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode, renderMode: RenderMode) {
- val typeParameters = node.details(DocumentationNode.Kind.TypeParameter)
- if (typeParameters.any()) {
- symbol("<")
- renderList(typeParameters) {
- renderTypeParameter(it, renderMode)
- }
- symbol(">")
- }
- }
-
- private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) {
- val supertypes = node.details(DocumentationNode.Kind.Supertype)
- if (supertypes.any()) {
- nbsp()
- symbol(":")
- nbsp()
- renderList(supertypes) {
- indentedSoftLineBreak()
- renderType(it, renderMode)
- }
- }
- }
-
- private fun ContentBlock.renderModifiersForNode(node: DocumentationNode,
- renderMode: RenderMode,
- nowrap: Boolean = false) {
- val modifiers = node.details(DocumentationNode.Kind.Modifier)
- for (it in modifiers) {
- if (node.kind == org.jetbrains.dokka.DocumentationNode.Kind.Interface && it.name == "abstract")
- continue
- if (renderMode == RenderMode.SUMMARY && it.name in fullOnlyModifiers) {
- continue
- }
- renderModifier(it, nowrap)
- }
- }
-
- private fun ContentBlock.renderAnnotationsForNode(node: DocumentationNode) {
- node.annotations.forEach {
- renderAnnotation(it)
- }
- }
-
- private fun ContentBlock.renderAnnotation(node: DocumentationNode) {
- identifier("@" + node.name, IdentifierKind.AnnotationName)
- val parameters = node.details(DocumentationNode.Kind.Parameter)
- if (!parameters.isEmpty()) {
- symbol("(")
- renderList(parameters) {
- text(it.detail(DocumentationNode.Kind.Value).name)
- }
- symbol(")")
- }
- text(" ")
- }
-
- private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- DocumentationNode.Kind.Class,
- DocumentationNode.Kind.AnnotationClass,
- DocumentationNode.Kind.Enum -> keyword("class ")
- DocumentationNode.Kind.Interface -> keyword("interface ")
- DocumentationNode.Kind.EnumItem -> keyword("enum val ")
- DocumentationNode.Kind.Object -> keyword("object ")
- else -> throw IllegalArgumentException("Node $node is not a class-like object")
- }
-
- identifierOrDeprecated(node)
- renderTypeParametersForNode(node, renderMode)
- renderSupertypesForNode(node, renderMode)
- }
-
- private fun ContentBlock.renderFunction(node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- DocumentationNode.Kind.Constructor -> identifier(node.owner!!.name)
- DocumentationNode.Kind.Function,
- DocumentationNode.Kind.CompanionObjectFunction -> keyword("fun ")
- else -> throw IllegalArgumentException("Node $node is not a function-like object")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(DocumentationNode.Kind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- if (node.kind != org.jetbrains.dokka.DocumentationNode.Kind.Constructor)
- identifierOrDeprecated(node)
-
- symbol("(")
- val parameters = node.details(DocumentationNode.Kind.Parameter)
- renderList(parameters) {
- indentedSoftLineBreak()
- renderParameter(it, renderMode)
- }
- if (needReturnType(node)) {
- if (parameters.isNotEmpty()) {
- softLineBreak()
- }
- symbol(")")
- symbol(": ")
- renderType(node.detail(DocumentationNode.Kind.Type), renderMode)
- }
- else {
- symbol(")")
- }
- }
-
- private fun ContentBlock.renderReceiver(node: DocumentationNode, renderMode: RenderMode, signatureMapper: SignatureMapper?) {
- val receiver = node.details(DocumentationNode.Kind.Receiver).singleOrNull()
- if (receiver != null) {
- if (signatureMapper != null) {
- signatureMapper.renderReceiver(receiver, this)
- } else {
- renderType(receiver.detail(DocumentationNode.Kind.Type), renderMode)
- }
- symbol(".")
- }
- }
-
- private fun needReturnType(node: DocumentationNode) = when(node.kind) {
- DocumentationNode.Kind.Constructor -> false
- else -> !node.isUnitReturnType()
- }
-
- fun DocumentationNode.isUnitReturnType(): Boolean =
- detail(DocumentationNode.Kind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit"
-
- private fun ContentBlock.renderProperty(node: DocumentationNode,
- renderMode: RenderMode,
- signatureMapper: SignatureMapper? = null) {
- if (renderMode == RenderMode.FULL) {
- renderAnnotationsForNode(node)
- }
- renderModifiersForNode(node, renderMode)
- when (node.kind) {
- DocumentationNode.Kind.Property,
- DocumentationNode.Kind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ")
- else -> throw IllegalArgumentException("Node $node is not a property")
- }
- renderTypeParametersForNode(node, renderMode)
- if (node.details(DocumentationNode.Kind.TypeParameter).any()) {
- text(" ")
- }
-
- renderReceiver(node, renderMode, signatureMapper)
-
- identifierOrDeprecated(node)
- symbol(": ")
- renderType(node.detail(DocumentationNode.Kind.Type), renderMode)
- }
-
- fun DocumentationNode.getPropertyKeyword() =
- if (details(DocumentationNode.Kind.Modifier).any { it.name == "var" }) "var" else "val"
-
- fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) {
- if (node.deprecation != null) {
- val strike = ContentStrikethrough()
- strike.identifier(node.name)
- append(strike)
- } else {
- identifier(node.name)
- }
- }
-}
-
-fun DocumentationNode.qualifiedNameFromType() = (links.firstOrNull() ?: hiddenLinks.firstOrNull())?.qualifiedName() ?: name