K2: Add extension point for additional KDoc resolution
Similar to K1 KDocLinkResolutionService used by Fe10KDocReference (to
support additional KDoc resolution), this commit adds K2 counterpart
AdditionalKDocResolutionProvider and uses it for KDocReferenceResolver.
^KT-62187
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt
index 4b8f637..b2069f5 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/references/KDocReferenceResolver.kt
@@ -10,12 +10,13 @@
import org.jetbrains.kotlin.analysis.api.components.KtScopeKind
import org.jetbrains.kotlin.analysis.api.scopes.KtScope
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.KtDeclarationSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
-import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
+import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
-import org.jetbrains.kotlin.name.*
+import org.jetbrains.kotlin.name.CallableId
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
import kotlin.reflect.KClass
@@ -82,6 +83,7 @@
getExtensionReceiverSymbolByThisQualifier(fqName, contextElement).ifNotEmpty { return this }
(getSymbolsFromScopes(fqName, contextElement) + listOfNotNull(getPackageSymbolIfPackageExists(fqName))).ifNotEmpty { return this }
getNonImportedSymbolsByFullyQualifiedName(fqName).ifNotEmpty { return this }
+ AdditionalKDocResolutionProvider.resolveKdocFqName(fqName, contextElement).ifNotEmpty { return this }
return emptyList()
}
diff --git a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt
index 3f5fe0c..f5f7e3e 100644
--- a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt
+++ b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt
@@ -33,6 +33,7 @@
import org.jetbrains.kotlin.analysis.api.impl.base.references.HLApiReferenceProviderService
import org.jetbrains.kotlin.analysis.api.impl.base.util.LibraryUtils
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
+import org.jetbrains.kotlin.analysis.api.symbols.AdditionalKDocResolutionProvider
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProvider
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInsVirtualFileProviderCliImpl
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
@@ -141,15 +142,26 @@
) {
val applicationArea = applicationEnvironment.application.extensionArea
- if (applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) return
- KotlinCoreEnvironment.underApplicationLock {
- if (applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) return@underApplicationLock
- CoreApplicationEnvironment.registerApplicationExtensionPoint(
- ClassTypePointerFactory.EP_NAME,
- ClassTypePointerFactory::class.java
- )
- applicationArea.getExtensionPoint(ClassTypePointerFactory.EP_NAME)
- .registerExtension(PsiClassReferenceTypePointerFactory(), applicationDisposable)
+ if (!applicationArea.hasExtensionPoint(AdditionalKDocResolutionProvider.EP_NAME)) {
+ KotlinCoreEnvironment.underApplicationLock {
+ if (applicationArea.hasExtensionPoint(AdditionalKDocResolutionProvider.EP_NAME)) return@underApplicationLock
+ CoreApplicationEnvironment.registerApplicationExtensionPoint(
+ AdditionalKDocResolutionProvider.EP_NAME,
+ AdditionalKDocResolutionProvider::class.java
+ )
+ }
+ }
+
+ if (!applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) {
+ KotlinCoreEnvironment.underApplicationLock {
+ if (applicationArea.hasExtensionPoint(ClassTypePointerFactory.EP_NAME)) return@underApplicationLock
+ CoreApplicationEnvironment.registerApplicationExtensionPoint(
+ ClassTypePointerFactory.EP_NAME,
+ ClassTypePointerFactory::class.java
+ )
+ applicationArea.getExtensionPoint(ClassTypePointerFactory.EP_NAME)
+ .registerExtension(PsiClassReferenceTypePointerFactory(), applicationDisposable)
+ }
}
}
diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/AdditionalKDocResolutionProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/AdditionalKDocResolutionProvider.kt
new file mode 100644
index 0000000..81270e6
--- /dev/null
+++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/symbols/AdditionalKDocResolutionProvider.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.analysis.api.symbols
+
+import com.intellij.openapi.extensions.ExtensionPointName
+import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.KtElement
+
+/**
+ * An extension point to provide additional symbols for a KDoc reference. KDoc link resolution will use symbols returned by this EP
+ * only if the real resolution was unsuccessful. You can use this EP by creating a class implementing this interface.
+ * For example, let's assume that you want to return symbol `fun foo() = 3` for the following KDoc resolution:
+ *
+ * ```
+ * package com.example
+ * fun foo() = 3
+ * /**
+ * * [this.is.not.com.example.fo<caret>o] is not the above `com.example.foo`, but you want to resolve it to the above `com.example.foo`.
+ * */
+ * fun bar() = 7
+ * ```
+ *
+ * You can create
+ *
+ * ```
+ * class AdditionalKDocResolutionProviderBasedOnNameMatch : AdditionalKDocResolutionProvider {
+ * context(KtAnalysisSession)
+ * override fun resolveKdocFqName(fqName: FqName, contextElement: KtElement): Collection<KtSymbol> =
+ * contextElement.containingKtFile.declarations.filter { it.name == fqName.shortName().asString() }.map { it.getSymbol() }
+ * }
+ * ```
+ */
+public interface AdditionalKDocResolutionProvider {
+ /**
+ * This function must return additional symbols for [contextElement] in KDoc.
+ */
+ context(KtAnalysisSession)
+ public fun resolveKdocFqName(fqName: FqName, contextElement: KtElement): Collection<KtSymbol>
+
+ public companion object {
+ public val EP_NAME: ExtensionPointName<AdditionalKDocResolutionProvider> =
+ ExtensionPointName<AdditionalKDocResolutionProvider>("org.jetbrains.kotlin.analysis.additionalKDocResolutionProvider")
+
+ context(KtAnalysisSession)
+ public fun resolveKdocFqName(fqName: FqName, contextElement: KtElement): Collection<KtSymbol> =
+ EP_NAME.extensions.flatMap { it.resolveKdocFqName(fqName, contextElement) }
+ }
+}
\ No newline at end of file