aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/translators/psi/parsers
diff options
context:
space:
mode:
authorVsevolod Tolstopyatov <qwwdfsad@gmail.com>2023-03-21 06:48:22 -0700
committerGitHub <noreply@github.com>2023-03-21 16:48:22 +0300
commitff5aa6721063599d8b68a245c482621b0d110fc6 (patch)
tree49b6a876ec0793a86ccd9c0e5284038072cea6b3 /plugins/base/src/main/kotlin/translators/psi/parsers
parente66f9d8711b5c1ba5e75fdcde8cfe998042c294a (diff)
downloaddokka-ff5aa6721063599d8b68a245c482621b0d110fc6.tar.gz
dokka-ff5aa6721063599d8b68a245c482621b0d110fc6.tar.bz2
dokka-ff5aa6721063599d8b68a245c482621b0d110fc6.zip
Improve JavadocParser and fix case-sensitivity (#2905)
* Get rid of safeEnumValueOf that was an unnecessary public API burden and constantly allocating * Restructure JavadocParser.parseDocTag, so it has one lever of nesting less * Make tag parsing case-sensitive Fixes #2907
Diffstat (limited to 'plugins/base/src/main/kotlin/translators/psi/parsers')
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt164
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt14
2 files changed, 101 insertions, 77 deletions
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 6a39652a..4af8c790 100644
--- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt
@@ -16,7 +16,6 @@ import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.doc.*
import org.jetbrains.dokka.model.doc.Deprecated
import org.jetbrains.dokka.utilities.DokkaLogger
-import org.jetbrains.dokka.utilities.enumValueOrNull
import org.jetbrains.dokka.utilities.htmlEscape
import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
import org.jetbrains.kotlin.idea.base.utils.fqname.getKotlinFqName
@@ -84,93 +83,106 @@ class JavadocParser(
parseWithChildren = parseWithChildren
)
- private fun parseDocTag(tag: PsiDocTag, docComment: PsiDocComment, analysedElement: PsiNamedElement): TagWrapper =
- enumValueOrNull<JavadocTag>(tag.name)?.let { javadocTag ->
- val resolutionContext = CommentResolutionContext(comment = docComment, tag = javadocTag)
- when (resolutionContext.tag) {
- JavadocTag.PARAM -> {
- val name = tag.dataElements.firstOrNull()?.text.orEmpty()
- val index =
- (analysedElement as? PsiMethod)?.parameterList?.parameters?.map { it.name }?.indexOf(name)
- Param(
- wrapTagIfNecessary(
- convertJavadocElements(
- tag.contentElementsWithSiblingIfNeeded().drop(1),
- context = resolutionContext.copy(name = name, parameterIndex = index)
- )
- ),
- name
- )
- }
- JavadocTag.THROWS, JavadocTag.EXCEPTION -> {
- val resolved = tag.resolveToElement()
- val dri = resolved?.let { DRI.from(it) }
- val name = resolved?.getKotlinFqName()?.asString()
- ?: tag.dataElements.firstOrNull()?.text.orEmpty()
- Throws(
- root = wrapTagIfNecessary(
- convertJavadocElements(
- tag.dataElements.drop(1),
- context = resolutionContext.copy(name = name)
- )
- ),
- /* we always would like to have a fully qualified name as name,
+ private fun parseDocTag(tag: PsiDocTag, docComment: PsiDocComment, analysedElement: PsiNamedElement): TagWrapper {
+ val javadocTag = JavadocTag.lowercaseValueOfOrNull(tag.name)
+ if (javadocTag == null) {
+ return emptyTagWrapper(tag, docComment)
+ }
+ // Javadoc tag found
+ val resolutionContext = CommentResolutionContext(comment = docComment, tag = javadocTag)
+ return when (resolutionContext.tag) {
+ JavadocTag.PARAM -> {
+ val name = tag.dataElements.firstOrNull()?.text.orEmpty()
+ val index =
+ (analysedElement as? PsiMethod)?.parameterList?.parameters?.map { it.name }?.indexOf(name)
+ Param(
+ wrapTagIfNecessary(
+ convertJavadocElements(
+ tag.contentElementsWithSiblingIfNeeded().drop(1),
+ context = resolutionContext.copy(name = name, parameterIndex = index)
+ )
+ ),
+ name
+ )
+ }
+
+ JavadocTag.THROWS, JavadocTag.EXCEPTION -> {
+ val resolved = tag.resolveToElement()
+ val dri = resolved?.let { DRI.from(it) }
+ val name = resolved?.getKotlinFqName()?.asString()
+ ?: tag.dataElements.firstOrNull()?.text.orEmpty()
+ Throws(
+ root = wrapTagIfNecessary(
+ convertJavadocElements(
+ tag.dataElements.drop(1),
+ context = resolutionContext.copy(name = name)
+ )
+ ),
+ /* we always would like to have a fully qualified name as name,
* because it will be used as a display name later and we would like to have those unified
* even if documentation states shortened version
*
* Only if dri search fails we should use the provided phrase (since then we are not able to get a fq name)
* */
- name = name,
- exceptionAddress = dri
+ name = name,
+ exceptionAddress = dri
+ )
+ }
+
+ JavadocTag.RETURN -> Return(
+ wrapTagIfNecessary(
+ convertJavadocElements(
+ tag.contentElementsWithSiblingIfNeeded(),
+ context = resolutionContext
)
- }
- JavadocTag.RETURN -> Return(
- wrapTagIfNecessary(
- convertJavadocElements(
- tag.contentElementsWithSiblingIfNeeded(),
- context = resolutionContext
- )
+ )
+ )
+
+ JavadocTag.AUTHOR -> Author(
+ wrapTagIfNecessary(
+ convertJavadocElements(
+ tag.contentElementsWithSiblingIfNeeded(),
+ context = resolutionContext
)
)
- JavadocTag.AUTHOR -> Author(
- wrapTagIfNecessary(
- convertJavadocElements(
- tag.contentElementsWithSiblingIfNeeded(),
- context = resolutionContext
- )
+ ) // Workaround: PSI returns first word after @author tag as a `DOC_TAG_VALUE_ELEMENT`, then the rest as a `DOC_COMMENT_DATA`, so for `Name Surname` we get them parted
+ JavadocTag.SEE -> {
+ val name =
+ tag.resolveToElement()?.getKotlinFqName()?.asString() ?: tag.referenceElement()?.text.orEmpty()
+ .removePrefix("#")
+ getSeeTagElementContent(tag, resolutionContext.copy(name = name)).let {
+ See(
+ wrapTagIfNecessary(it.first),
+ name,
+ it.second
)
- ) // Workaround: PSI returns first word after @author tag as a `DOC_TAG_VALUE_ELEMENT`, then the rest as a `DOC_COMMENT_DATA`, so for `Name Surname` we get them parted
- JavadocTag.SEE -> {
- val name =
- tag.resolveToElement()?.getKotlinFqName()?.asString() ?: tag.referenceElement()?.text.orEmpty().removePrefix("#")
- getSeeTagElementContent(tag, resolutionContext.copy(name = name)).let {
- See(
- wrapTagIfNecessary(it.first),
- name,
- it.second
- )
- }
}
- JavadocTag.DEPRECATED -> Deprecated(
- wrapTagIfNecessary(
- convertJavadocElements(
- tag.contentElementsWithSiblingIfNeeded(),
- context = resolutionContext
- )
- )
- )
- else -> null
- //TODO https://github.com/Kotlin/dokka/issues/1618
}
- } ?: CustomTagWrapper(
- wrapTagIfNecessary(
- convertJavadocElements(
- tag.contentElementsWithSiblingIfNeeded(),
- context = CommentResolutionContext(docComment, null)
+
+ JavadocTag.DEPRECATED -> Deprecated(
+ wrapTagIfNecessary(
+ convertJavadocElements(
+ tag.contentElementsWithSiblingIfNeeded(),
+ context = resolutionContext
+ )
)
- ),
- tag.name
- )
+ )
+
+ else -> emptyTagWrapper(tag, docComment)
+ }
+ }
+
+ // Wrapper for unsupported tags https://github.com/Kotlin/dokka/issues/1618
+ private fun emptyTagWrapper(
+ tag: PsiDocTag,
+ docComment: PsiDocComment
+ ) = CustomTagWrapper(
+ wrapTagIfNecessary(
+ convertJavadocElements(
+ tag.contentElementsWithSiblingIfNeeded(),
+ context = CommentResolutionContext(docComment, null)
+ )), tag.name
+ )
private fun wrapTagIfNecessary(list: List<DocTag>): CustomDocTag =
if (list.size == 1 && (list.first() as? CustomDocTag)?.name == MarkdownElementTypes.MARKDOWN_FILE.name)
diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt
index 869ced30..747e2efe 100644
--- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt
@@ -17,4 +17,16 @@ internal enum class JavadocTag {
SINCE,
VERSION
*/
-} \ No newline at end of file
+
+ companion object {
+ private val name2Value = values().associateBy { it.name.toLowerCase() }
+
+ /**
+ * Lowercase-based `Enum.valueOf` variation for [JavadocTag].
+ *
+ * Note: tags are [case-sensitive](https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javadoc.html) in Java,
+ * thus we are not allowed to use case-insensitive or uppercase-based lookup.
+ */
+ fun lowercaseValueOfOrNull(name: String): JavadocTag? = name2Value[name]
+ }
+}