Skip to content

Commit e9e8fbf

Browse files
authored
[K2] Fix functional type and improve logging for unresolved link (#3157)
* [K2] Fix functional type and improve logging for unresolved link For example `typealias CompletionHandler = (cause: Throwable?) -> Unit` has a functional type with no type arguments in K2. In K1 we have a usual generic type
1 parent 8065a0d commit e9e8fbf

7 files changed

Lines changed: 65 additions & 26 deletions

File tree

plugins/base/src/test/kotlin/translators/ExternalDocumentablesTest.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import org.jetbrains.dokka.plugability.querySingle
1414
import org.jetbrains.dokka.utilities.cast
1515
import kotlin.test.Test
1616
import kotlin.test.assertEquals
17-
import utils.OnlyDescriptors
1817
import utils.UsingJDK
1918

2019
class ExternalDocumentablesTest : BaseAbstractTest() {
@@ -61,10 +60,6 @@ class ExternalDocumentablesTest : BaseAbstractTest() {
6160
}
6261
}
6362

64-
65-
// typealias CompletionHandler = (cause: Throwable?) -> Unit
66-
// FunctionalTypeConstructor(dri=kotlinx.coroutines/CompletionHandler///PointingToDeclaration/, projections=[], isExtensionFunction=false, isSuspendable=false, presentableName=null, extra=PropertyContainer(map={}))
67-
@OnlyDescriptors(reason = "FunctionType has not parameters") // TODO
6863
@Test
6964
fun `external documentable from dependency`() {
7065
val coroutinesPath =

subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/KDocProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ internal fun KtAnalysisSession.getKDocDocumentationFrom(symbol: KtSymbol, logger
6464

6565
parseFromKDocTag(
6666
kDocTag = kDocContent.contentTag,
67-
externalDri = { link -> resolveKDocLink(link).logIfNotResolved(link.getLinkText(), logger) },
67+
externalDri = { link -> resolveKDocLink(link).ifUnresolved { logger.logUnresolvedLink(link.getLinkText(), kdocLocation) } },
6868
kdocLocation = kdocLocation
6969
)
7070
}

subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/ResolveKDocLink.kt

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,24 @@ import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
1515
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
1616
import org.jetbrains.kotlin.psi.KtPsiFactory
1717

18-
internal fun DRI?.logIfNotResolved(link: String, logger: DokkaLogger): DRI? {
19-
if(this == null)
20-
logger.warn("Couldn't resolve link for $link")
21-
return this
18+
/**
19+
* Util to print a message about unresolved [link]
20+
*/
21+
internal fun DokkaLogger.logUnresolvedLink(link: String, location: String?) {
22+
warn("Couldn't resolve link for $link" + if (location != null) " in $location" else "")
23+
}
24+
25+
internal inline fun DRI?.ifUnresolved(action: () -> Unit): DRI? = this ?: run {
26+
action()
27+
null
2228
}
2329

2430
/**
25-
* It resolves KDoc link via creating PSI.
31+
* Resolves KDoc link via creating PSI.
32+
* If the [link] is ambiguous, i.e. leads to more than one declaration,
33+
* it returns deterministically any declaration.
2634
*
35+
* @return [DRI] or null if the [link] is unresolved
2736
*/
2837
internal fun KtAnalysisSession.resolveKDocTextLink(link: String, context: PsiElement? = null): DRI? {
2938
val psiFactory = context?.let { KtPsiFactory.contextual(it) } ?: KtPsiFactory(this.useSiteModule.project)
@@ -38,9 +47,15 @@ internal fun KtAnalysisSession.resolveKDocTextLink(link: String, context: PsiEle
3847
return kDocLink?.let { resolveKDocLink(it) }
3948
}
4049

50+
/**
51+
* If the [link] is ambiguous, i.e. leads to more than one declaration,
52+
* it returns deterministically any declaration.
53+
*
54+
* @return [DRI] or null if the [link] is unresolved
55+
*/
4156
internal fun KtAnalysisSession.resolveKDocLink(link: KDocLink): DRI? {
4257
val lastNameSegment = link.children.filterIsInstance<KDocName>().lastOrNull()
4358
val linkedSymbol = lastNameSegment?.mainReference?.resolveToSymbols()?.firstOrNull()
44-
return if (linkedSymbol == null) null // logger.warn("Couldn't resolve link for $link")
59+
return if (linkedSymbol == null) null
4560
else getDRIFromSymbol(linkedSymbol)
4661
}

subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/java/KotlinDocCommentParser.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ import com.intellij.psi.PsiNamedElement
88
import org.jetbrains.dokka.Platform
99
import org.jetbrains.dokka.analysis.java.doccomment.DocComment
1010
import org.jetbrains.dokka.analysis.java.parsers.DocCommentParser
11-
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logIfNotResolved
12-
import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin
11+
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.*
12+
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logUnresolvedLink
1313
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.parseFromKDocTag
1414
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.resolveKDocLink
15+
import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.SymbolsAnalysisPlugin
1516
import org.jetbrains.dokka.model.doc.DocumentationNode
1617
import org.jetbrains.dokka.plugability.DokkaContext
1718
import org.jetbrains.dokka.plugability.plugin
@@ -37,10 +38,11 @@ internal class KotlinDocCommentParser(
3738
?: sourceSets.first { it.analysisPlatform == Platform.jvm }
3839
}
3940
val kotlinAnalysis = context.plugin<SymbolsAnalysisPlugin>().querySingle { kotlinAnalysis }
41+
val elementName = element.resolveDocContext.ktElement.name
4042
return analyze(kotlinAnalysis[sourceSet].mainModule) {
4143
parseFromKDocTag(
4244
kDocTag = element.comment,
43-
externalDri = { link -> resolveKDocLink(link).logIfNotResolved(link.getLinkText(), context.logger) },
45+
externalDri = { link -> resolveKDocLink(link).ifUnresolved { context.logger.logUnresolvedLink(link.getLinkText(), elementName) } },
4446
kdocLocation = null,
4547
parseWithChildren = parseWithChildren
4648
)

subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/kdoc/moduledocs/ModuleAndPackageDocumentationParsingContext.kt

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
package org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs
66

77
import org.jetbrains.dokka.DokkaConfiguration
8-
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logIfNotResolved
8+
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.ifUnresolved
9+
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.logUnresolvedLink
910
import org.jetbrains.dokka.analysis.kotlin.symbols.plugin.KotlinAnalysis
1011
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Module
1112
import org.jetbrains.dokka.analysis.kotlin.symbols.kdoc.moduledocs.ModuleAndPackageDocumentation.Classifier.Package
@@ -32,20 +33,31 @@ internal fun ModuleAndPackageDocumentationParsingContext(
3233
sourceSet: DokkaConfiguration.DokkaSourceSet? = null
3334
) = ModuleAndPackageDocumentationParsingContext { fragment, sourceLocation ->
3435

35-
if(kotlinAnalysis == null || sourceSet == null) {
36+
if (kotlinAnalysis == null || sourceSet == null) {
3637
MarkdownParser(externalDri = { null }, sourceLocation)
3738
} else {
3839
val analysisContext = kotlinAnalysis[sourceSet]
39-
analyze(analysisContext.mainModule) {
40+
val contextPsi = analyze(analysisContext.mainModule) {
4041
val contextSymbol = when (fragment.classifier) {
4142
Module -> ROOT_PACKAGE_SYMBOL
4243
Package -> getPackageSymbolIfPackageExists(FqName(fragment.name))
4344
}
44-
45-
MarkdownParser(
46-
externalDri = { resolveKDocTextLink(it, contextSymbol?.psi).logIfNotResolved(it, logger) },
47-
sourceLocation
48-
)
45+
contextSymbol?.psi
4946
}
47+
MarkdownParser(
48+
externalDri = { link ->
49+
analyze(analysisContext.mainModule) {
50+
resolveKDocTextLink(
51+
link,
52+
contextPsi
53+
).ifUnresolved {
54+
logger.logUnresolvedLink(link, fragment.name.ifBlank { "module documentation" })
55+
}
56+
57+
}
58+
},
59+
sourceLocation
60+
)
61+
5062
}
5163
}

subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/AnnotationTranslator.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ internal class AnnotationTranslator {
111111
DRI(packageName = "", classNames = ERROR_CLASS_NAME)
112112
)
113113

114-
KtUnsupportedAnnotationValue -> TODO()
114+
KtUnsupportedAnnotationValue -> ClassValue(
115+
"<Unsupported Annotation Value>",
116+
DRI(packageName = "", classNames = ERROR_CLASS_NAME)
117+
)
115118
}
116119

117120
private fun getDRIFrom(enumEntry: KtEnumEntryAnnotationValue): DRI {
@@ -129,6 +132,7 @@ internal class AnnotationTranslator {
129132

130133
/**
131134
* Functional types can have **generated** [ParameterName] annotation
135+
* @see ParameterName
132136
*/
133137
internal fun KtAnnotated.getPresentableName(): String? =
134138
this.annotationsByClassId(parameterNameAnnotation)

subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeTranslator.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ internal class TypeTranslator(
5252
throw IllegalStateException("Expected type alias symbol in type")
5353
}
5454

55-
private fun KtAnalysisSession.toTypeConstructorFrom(classType: KtUsualClassType) =
55+
private fun KtAnalysisSession.toTypeConstructorFrom(classType: KtNonErrorClassType) =
5656
GenericTypeConstructor(
5757
dri = getDRIFromNonErrorClassType(classType),
5858
projections = classType.ownTypeArguments.map { toProjection(it) },
@@ -91,7 +91,18 @@ internal class TypeTranslator(
9191
)
9292

9393
is KtClassErrorType -> UnresolvedBound(type.toString())
94-
is KtFunctionalType -> toFunctionalTypeConstructorFrom(type)
94+
is KtFunctionalType -> {
95+
/**
96+
* For example
97+
* `typealias CompletionHandler = (cause: Throwable?) -> Unit`
98+
* has functional type with no type arguments in K2
99+
* In K1 we have a usual generic type
100+
*/
101+
if (type.ownTypeArguments.isEmpty())
102+
toTypeConstructorFrom(type)
103+
else
104+
toFunctionalTypeConstructorFrom(type)
105+
}
95106
is KtDynamicType -> Dynamic
96107
is KtDefinitelyNotNullType -> DefinitelyNonNullable(
97108
toBoundFrom(type.original)

0 commit comments

Comments
 (0)