diff options
author | Vsevolod Tolstopyatov <qwwdfsad@gmail.com> | 2023-03-21 06:48:22 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-21 16:48:22 +0300 |
commit | ff5aa6721063599d8b68a245c482621b0d110fc6 (patch) | |
tree | 49b6a876ec0793a86ccd9c0e5284038072cea6b3 /plugins/base/src/main/kotlin/translators/psi/parsers | |
parent | e66f9d8711b5c1ba5e75fdcde8cfe998042c294a (diff) | |
download | dokka-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.kt | 164 | ||||
-rw-r--r-- | plugins/base/src/main/kotlin/translators/psi/parsers/JavadocTag.kt | 14 |
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] + } +} |