From 92aa97ae4727d3d086ef2481f223eb493a8d1103 Mon Sep 17 00:00:00 2001 From: IgnatBeresnev Date: Tue, 31 Oct 2023 23:06:00 +0100 Subject: [PATCH] Use `resolveKDocTextLink` to resolve sample links --- .../kotlin/symbols/kdoc/KDocProvider.kt | 2 +- .../kotlin/symbols/kdoc/ResolveKDocLink.kt | 33 +++++++++++++++---- .../symbols/kdoc/SyntheticKDocProvider.kt | 2 +- .../kdoc/java/KotlinDocCommentParser.kt | 4 +-- ...leAndPackageDocumentationParsingContext.kt | 4 +-- .../SymbolSampleAnalysisEnvironment.kt | 17 +++------- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt index d8a4e4769c0..36492cdd702 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt @@ -64,7 +64,7 @@ internal fun KtAnalysisSession.getKDocDocumentationFrom(symbol: KtSymbol, logger parseFromKDocTag( kDocTag = kDocContent.contentTag, - externalDri = { link -> resolveKDocLink(link).ifUnresolved { logger.logUnresolvedLink(link.getLinkText(), kdocLocation) } }, + externalDri = { link -> resolveKDocLinkDRI(link).ifUnresolved { logger.logUnresolvedLink(link.getLinkText(), kdocLocation) } }, kdocLocation = kdocLocation ) } diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt index 9a0b81bd5a2..c719c8550b6 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt @@ -9,6 +9,7 @@ import org.jetbrains.dokka.analysis.kotlin.symbols.translators.getDRIFromSymbol import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.kotlin.analysis.api.KtAnalysisSession +import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink @@ -34,7 +35,23 @@ internal inline fun DRI?.ifUnresolved(action: () -> Unit): DRI? = this ?: run { * * @return [DRI] or null if the [link] is unresolved */ -internal fun KtAnalysisSession.resolveKDocTextLink(link: String, context: PsiElement? = null): DRI? { +internal fun KtAnalysisSession.resolveKDocTextLinkDRI(link: String, context: PsiElement? = null): DRI? { + val kDocLink = createKDocLink(link, context) + return kDocLink?.let { resolveKDocLinkDRI(it) } +} + +/** + * If the [link] is ambiguous, i.e. leads to more than one declaration, + * it returns deterministically any declaration. + * + * @return [KtSymbol] or null if the [link] is unresolved + */ +internal fun KtAnalysisSession.resolveKDocTextLinkSymbol(link: String, context: PsiElement? = null): KtSymbol? { + val kDocLink = createKDocLink(link, context) + return kDocLink?.let { resolveToSymbol(it) } +} + +private fun KtAnalysisSession.createKDocLink(link: String, context: PsiElement? = null): KDocLink? { val psiFactory = context?.let { KtPsiFactory.contextual(it) } ?: KtPsiFactory(this.useSiteModule.project) val kDoc = psiFactory.createComment( """ @@ -43,8 +60,8 @@ internal fun KtAnalysisSession.resolveKDocTextLink(link: String, context: PsiEle */ """.trimIndent() ) as? KDoc - val kDocLink = kDoc?.getDefaultSection()?.children?.filterIsInstance()?.singleOrNull() - return kDocLink?.let { resolveKDocLink(it) } + + return kDoc?.getDefaultSection()?.children?.filterIsInstance()?.singleOrNull() } /** @@ -53,9 +70,13 @@ internal fun KtAnalysisSession.resolveKDocTextLink(link: String, context: PsiEle * * @return [DRI] or null if the [link] is unresolved */ -internal fun KtAnalysisSession.resolveKDocLink(link: KDocLink): DRI? { - val lastNameSegment = link.children.filterIsInstance().lastOrNull() - val linkedSymbol = lastNameSegment?.mainReference?.resolveToSymbols()?.firstOrNull() +internal fun KtAnalysisSession.resolveKDocLinkDRI(link: KDocLink): DRI? { + val linkedSymbol = resolveToSymbol(link) return if (linkedSymbol == null) null else getDRIFromSymbol(linkedSymbol) } + +private fun KtAnalysisSession.resolveToSymbol(kDocLink: KDocLink): KtSymbol? { + val lastNameSegment = kDocLink.children.filterIsInstance().lastOrNull() + return lastNameSegment?.mainReference?.resolveToSymbols()?.firstOrNull() +} diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/SyntheticKDocProvider.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/SyntheticKDocProvider.kt index 4622ffd8dfa..9f2e6873fbf 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/SyntheticKDocProvider.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/SyntheticKDocProvider.kt @@ -54,7 +54,7 @@ internal fun KtAnalysisSession.getGeneratedKDocDocumentationFrom(symbol: KtSymbo private fun KtAnalysisSession.loadTemplate(filePath: String): DocumentationNode? { val kdoc = loadContent(filePath) ?: return null val externalDriProvider = { link: String -> - resolveKDocTextLink(link) + resolveKDocTextLinkDRI(link) } val parser = MarkdownParser(externalDriProvider, filePath) diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt index 33cc43053f0..f4c32648f42 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt @@ -11,7 +11,7 @@ import org.jetbrains.dokka.analysis.java.parsers.DocCommentParser import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.* import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logUnresolvedLink import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.parseFromKDocTag -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocLink +import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocLinkDRI import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.plugability.DokkaContext @@ -42,7 +42,7 @@ internal class KotlinDocCommentParser( return analyze(kotlinAnalysis[sourceSet].mainModule) { parseFromKDocTag( kDocTag = element.comment, - externalDri = { link -> resolveKDocLink(link).ifUnresolved { context.logger.logUnresolvedLink(link.getLinkText(), elementName) } }, + externalDri = { link -> resolveKDocLinkDRI(link).ifUnresolved { context.logger.logUnresolvedLink(link.getLinkText(), elementName) } }, kdocLocation = null, parseWithChildren = parseWithChildren ) diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt index ef59aa339b1..51e0abb5ccb 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt @@ -10,7 +10,7 @@ import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logUnresolvedLink import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.KotlinAnalysis import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Module import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Package -import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocTextLink +import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocTextLinkDRI import org.jetbrains.dokka.analysis.markdown.jb.MarkdownParser import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.utilities.DokkaLogger @@ -47,7 +47,7 @@ internal fun ModuleAndPackageDocumentationParsingContext( MarkdownParser( externalDri = { link -> analyze(analysisContext.mainModule) { - resolveKDocTextLink( + resolveKDocTextLinkDRI( link, contextPsi ).ifUnresolved { diff --git a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt index 8918b9a2d4e..2ca715803b0 100644 --- a/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt +++ b/subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/services/SymbolSampleAnalysisEnvironment.kt @@ -8,19 +8,18 @@ import com.intellij.psi.PsiElement import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironment import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironmentCreator import org.jetbrains.dokka.analysis.kotlin.sample.SampleSnippet +import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocTextLinkSymbol import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.KotlinAnalysis import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SamplesKotlinAnalysis import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.kotlin.analysis.api.analyze -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.psi.KtFile @@ -79,13 +78,7 @@ private class SymbolSampleAnalysisEnvironment( private fun findPsiElement(sourceSet: DokkaSourceSet, fqLink: String): PsiElement? { val analysisContext = kotlinAnalysis[sourceSet] return analyze(analysisContext.mainModule) { - // TODO the logic below is incorrect as it assumes the samples can only link to top-level functions. - // TODO should be corrected to be able to work with functions inside classes. See Descriptor's impl. - val isRootPackage = !fqLink.contains('.') - val supposedFunctionName = if (isRootPackage) fqLink else fqLink.substringAfterLast(".") - val supposedPackageName = if (isRootPackage) "" else fqLink.substringBeforeLast(".") - - getTopLevelCallableSymbols(FqName(supposedPackageName), Name.identifier(supposedFunctionName)).firstOrNull()?.psi + resolveKDocTextLinkSymbol(fqLink)?.psi } }