aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2022-09-26 18:47:01 +0200
committerGitHub <noreply@github.com>2022-09-26 18:47:01 +0200
commit86f9559ebd40a07e996df49464fc9101dd21d3bc (patch)
tree88b91d93b49e3276b81143febb9cb381ab03b82d /plugins/base/src/main/kotlin
parent9207f8f032fac8036c9aa5aa65633341a14efa62 (diff)
downloaddokka-86f9559ebd40a07e996df49464fc9101dd21d3bc.tar.gz
dokka-86f9559ebd40a07e996df49464fc9101dd21d3bc.tar.bz2
dokka-86f9559ebd40a07e996df49464fc9101dd21d3bc.zip
Add documentation for synthetic Enum `values()` and `valueOf()` functions (#2650)
Diffstat (limited to 'plugins/base/src/main/kotlin')
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt15
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt47
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt15
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt39
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt5
5 files changed, 109 insertions, 12 deletions
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
index c52fbd37..e3e1a33e 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
@@ -136,6 +136,7 @@ private class DokkaDescriptorVisitor(
private val logger: DokkaLogger
) {
private val javadocParser = JavadocParser(logger, resolutionFacade)
+ private val syntheticDocProvider = SyntheticDescriptorDocumentationProvider(resolutionFacade)
private fun Collection<DeclarationDescriptor>.filterDescriptorsInSourceSet() = filter {
it.toSourceElement.containingFile.toString().let { path ->
@@ -577,8 +578,7 @@ private class DokkaDescriptorVisitor(
sources = actual,
visibility = descriptor.visibility.toDokkaVisibility().toSourceSetDependent(),
generics = generics.await(),
- documentation = descriptor.takeIf { it.kind != CallableMemberDescriptor.Kind.SYNTHESIZED }
- ?.resolveDescriptorData() ?: emptyMap(),
+ documentation = descriptor.getDocumentation(),
modifier = descriptor.modifier().toSourceSetDependent(),
type = descriptor.returnType!!.toBound(),
sourceSets = setOf(sourceSet),
@@ -594,6 +594,15 @@ private class DokkaDescriptorVisitor(
}
}
+ private fun FunctionDescriptor.getDocumentation(): SourceSetDependent<DocumentationNode> {
+ val isSynthesized = this.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
+ return if (isSynthesized) {
+ syntheticDocProvider.getDocumentation(this)?.toSourceSetDependent() ?: emptyMap()
+ } else {
+ this.resolveDescriptorData()
+ }
+ }
+
/**
* `createDRI` returns the DRI of the exact element and potential DRI of an element that is overriding it
* (It can be also FAKE_OVERRIDE which is in fact just inheritance of the symbol)
@@ -609,7 +618,7 @@ private class DokkaDescriptorVisitor(
private fun FunctionDescriptor.isObvious(): Boolean {
return kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE
- || kind == CallableMemberDescriptor.Kind.SYNTHESIZED
+ || (kind == CallableMemberDescriptor.Kind.SYNTHESIZED && !syntheticDocProvider.isDocumented(this))
|| containingDeclaration.fqNameOrNull()?.isObvious() == true
}
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt b/plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt
new file mode 100644
index 00000000..c96b888a
--- /dev/null
+++ b/plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt
@@ -0,0 +1,47 @@
+package org.jetbrains.dokka.base.translators.descriptors
+
+import org.jetbrains.dokka.analysis.DokkaResolutionFacade
+import org.jetbrains.dokka.analysis.from
+import org.jetbrains.dokka.base.parsers.MarkdownParser
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.doc.DocumentationNode
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
+import org.jetbrains.kotlin.resolve.DescriptorFactory
+
+private const val ENUM_VALUEOF_TEMPLATE_PATH = "/dokka/docs/kdoc/EnumValueOf.kt.template"
+private const val ENUM_VALUES_TEMPLATE_PATH = "/dokka/docs/kdoc/EnumValues.kt.template"
+
+ internal class SyntheticDescriptorDocumentationProvider(
+ private val resolutionFacade: DokkaResolutionFacade
+) {
+ fun isDocumented(descriptor: DeclarationDescriptor): Boolean = descriptor is FunctionDescriptor
+ && (DescriptorFactory.isEnumValuesMethod(descriptor) || DescriptorFactory.isEnumValueOfMethod(descriptor))
+
+ fun getDocumentation(descriptor: DeclarationDescriptor): DocumentationNode? {
+ val function = descriptor as? FunctionDescriptor ?: return null
+ return when {
+ DescriptorFactory.isEnumValuesMethod(function) -> loadTemplate(descriptor, ENUM_VALUES_TEMPLATE_PATH)
+ DescriptorFactory.isEnumValueOfMethod(function) -> loadTemplate(descriptor, ENUM_VALUEOF_TEMPLATE_PATH)
+ else -> null
+ }
+ }
+
+ private fun loadTemplate(descriptor: DeclarationDescriptor, filePath: String): DocumentationNode? {
+ val kdoc = loadContent(filePath) ?: return null
+ val parser = MarkdownParser({ link -> resolveLink(descriptor, link)}, filePath)
+ return parser.parse(kdoc)
+ }
+
+ private fun loadContent(filePath: String): String? = javaClass.getResource(filePath)?.readText()
+
+ private fun resolveLink(descriptor: DeclarationDescriptor, link: String): DRI? =
+ resolveKDocLink(
+ resolutionFacade.resolveSession.bindingContext,
+ resolutionFacade,
+ descriptor,
+ null,
+ link.split('.')
+ ).firstOrNull()?.let { DRI.from(it) }
+}
diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
index 58524479..574fb2e8 100644
--- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
@@ -8,8 +8,6 @@ import com.intellij.lang.jvm.annotation.JvmAnnotationEnumFieldValue
import com.intellij.lang.jvm.types.JvmReferenceType
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.*
-import com.intellij.psi.impl.source.PsiClassReferenceType
-import com.intellij.psi.impl.source.PsiImmediateClassType
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
@@ -99,8 +97,8 @@ class DefaultPsiToDocumentableTranslator(
facade: DokkaResolutionFacade,
private val logger: DokkaLogger
) {
-
- private val javadocParser: JavaDocumentationParser = JavadocParser(logger, facade)
+ private val javadocParser = JavadocParser(logger, facade)
+ private val syntheticDocProvider = SyntheticElementDocumentationProvider(javadocParser, facade)
private val cachedBounds = hashMapOf<String, Bound>()
@@ -404,7 +402,7 @@ class DefaultPsiToDocumentableTranslator(
val dri = parentDRI?.let { dri ->
DRI.from(psi).copy(packageName = dri.packageName, classNames = dri.classNames)
} ?: DRI.from(psi)
- val docs = javadocParser.parseDocumentation(psi)
+ val docs = psi.getDocumentation()
return DFunction(
dri = dri,
name = psi.name,
@@ -452,8 +450,13 @@ class DefaultPsiToDocumentableTranslator(
)
}
+ private fun PsiMethod.getDocumentation(): DocumentationNode =
+ this.takeIf { it is SyntheticElement }?.let { syntheticDocProvider.getDocumentation(it) }
+ ?: javadocParser.parseDocumentation(this)
+
private fun PsiMethod.isObvious(inheritedFrom: DRI? = null): Boolean {
- return this is SyntheticElement || inheritedFrom?.isObvious() == true
+ return (this is SyntheticElement && !syntheticDocProvider.isDocumented(this))
+ || inheritedFrom?.isObvious() == true
}
private fun DRI.isObvious(): Boolean {
diff --git a/plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt b/plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt
new file mode 100644
index 00000000..376c0940
--- /dev/null
+++ b/plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt
@@ -0,0 +1,39 @@
+package org.jetbrains.dokka.base.translators.psi
+
+import com.intellij.psi.*
+import com.intellij.psi.javadoc.PsiDocComment
+import org.jetbrains.dokka.analysis.DokkaResolutionFacade
+import org.jetbrains.dokka.base.translators.psi.parsers.JavadocParser
+import org.jetbrains.dokka.model.doc.DocumentationNode
+
+private const val ENUM_VALUEOF_TEMPLATE_PATH = "/dokka/docs/javadoc/EnumValueOf.java.template"
+private const val ENUM_VALUES_TEMPLATE_PATH = "/dokka/docs/javadoc/EnumValues.java.template"
+
+internal class SyntheticElementDocumentationProvider(
+ private val javadocParser: JavadocParser,
+ private val resolutionFacade: DokkaResolutionFacade
+) {
+ fun isDocumented(psiElement: PsiElement): Boolean = psiElement is PsiMethod
+ && (psiElement.isSyntheticEnumValuesMethod() || psiElement.isSyntheticEnumValueOfMethod())
+
+ fun getDocumentation(psiElement: PsiElement): DocumentationNode? {
+ val psiMethod = psiElement as? PsiMethod ?: return null
+ val templatePath = when {
+ psiMethod.isSyntheticEnumValuesMethod() -> ENUM_VALUES_TEMPLATE_PATH
+ psiMethod.isSyntheticEnumValueOfMethod() -> ENUM_VALUEOF_TEMPLATE_PATH
+ else -> return null
+ }
+ val docComment = loadSyntheticDoc(templatePath) ?: return null
+ return javadocParser.parseDocComment(docComment, psiElement)
+ }
+
+ private fun loadSyntheticDoc(path: String): PsiDocComment? {
+ val text = javaClass.getResource(path)?.readText() ?: return null
+ return JavaPsiFacade.getElementFactory(resolutionFacade.project).createDocCommentFromText(text)
+ }
+}
+
+private fun PsiMethod.isSyntheticEnumValuesMethod() = this.isSyntheticEnumFunction() && this.name == "values"
+private fun PsiMethod.isSyntheticEnumValueOfMethod() = this.isSyntheticEnumFunction() && this.name == "valueOf"
+private fun PsiMethod.isSyntheticEnumFunction() = this is SyntheticElement && this.containingClass?.isEnum == true
+
diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt
index 076d43a2..6a39652a 100644
--- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt
@@ -50,14 +50,13 @@ class JavadocParser(
override fun parseDocumentation(element: PsiNamedElement): DocumentationNode {
return when(val comment = findClosestDocComment(element, logger)){
- is JavaDocComment -> parseDocumentation(comment, element)
+ is JavaDocComment -> parseDocComment(comment.comment, element)
is KotlinDocComment -> parseDocumentation(comment)
else -> DocumentationNode(emptyList())
}
}
- private fun parseDocumentation(element: JavaDocComment, context: PsiNamedElement): DocumentationNode {
- val docComment = element.comment
+ internal fun parseDocComment(docComment: PsiDocComment, context: PsiNamedElement): DocumentationNode {
val nodes = listOfNotNull(docComment.getDescription()) + docComment.tags.mapNotNull { tag ->
parseDocTag(tag, docComment, context)
}